//: Playground - noun: a place where people can play

import UIKit

//: 闭包: 用来捕获,存储传递代码块以及常量和变量的引用
let nums = [4, 6, 2, 9, 5]
let sortNums = nums.sorted()

func backward(s1: Int,s2: Int) -> Bool {
    // 定义sorted规则
    return s1 > s2   // 传入类型和nums元素一致,返回布尔值
}
// 将backward当作参数传入
let sortNums1 = nums.sorted(by: backward) // [9, 6, 5, 4, 2]

// 利用闭包去实现,闭包表达语法:
// { (参数名1: 参数类型, 参数名2: 参数类型) -> 返回类型 in
//     代码块
//     return 返回值
// }

let sortNums2 = nums.sorted(by: {(s1:Int,s2:Int) -> Bool in
    return s1 > s2
})


//:  闭包的简化
let sortNums3 = nums.sorted(by: {s1,s2 in return s1<s2})
print(sortNums3)

let sortNum4 = nums.sorted(by: {s1,s2 in s1<s2})
print(sortNum4)

let sortNum5 = nums.sorted(by: {$0 < $1})
print(sortNum5)

let sortNum6 = nums.sorted(by: <)
print(sortNum6)



//:   尾随闭包:调用函数时,要将闭包作为函数的参数传递,如果太长可以写在函数括号之后
let sortNums7 = nums.sorted() { $0 > $1 } // 使用尾随闭包调用函数
print(sortNums7)                       // [9, 6, 5, 4, 2]
let sortNums8 = nums.sorted { $0 > $1 } // 这个函数只有一个参数,且是闭包表达式,还可以省略()
print(sortNums8)                       // [9, 6, 5, 4, 2]


//:  值捕获: 捕获变量或常量
func makeAdd(forAdd amount: Int) -> () -> Int{
    var total = 0
    func add() -> Int {
        total += amount
        return total
    }
    return add
}

let addTen = makeAdd(forAdd: 10)       // 定义了一个常量,相当于持续持有add()函数
addTen()                               // 10, 每一次调用都会将total增加10
addTen()                               // 20

let addSeven = makeAdd(forAdd: 7)      // 开辟持有了一块新的内存
addSeven()                             // 7


//:   逃逸闭包: 当一个闭包作为参数传到一个函数中,这个闭包要在函数返回的时候才会被执行
var handlers : [() -> Void] = []
func funcWithEscaping(handle: @escaping () -> Void){// 外部定义的闭包需要添加标记@escaping
    handlers.append(handle)
}

func funcWithNoneEscaping(closure : () -> Void){
    closure()
}

class tempClass{
    var x = 10
    func doSomething() {
        funcWithEscaping {
            self.x = 100 // 加了@escaping标记,需要显式引用self
        }
        funcWithNoneEscaping {
            x = 200
        }
    }
}

let instance = tempClass()
instance.doSomething()
print(instance.x)

handlers.first?()
print(instance.x)


//:  1.自动闭包: 一种自动创建的闭包,用来当作函数的参数     2.自动闭包只有在调用的时候,闭包中的代码才会被执行  3.这种闭包不接受任何参数,被调用的时候会返回被包装在其中的表达式的值
var names = ["Chars", "Alex", "Olliver", "Barry"]
names.count
let customer = {names.remove(at: 0)}
names.count
customer()
names.count
print(names)

func serve(customer : () -> String){
    customer()    // 执行参数闭包
}
serve(customer: {names.remove(at: 0)})
names.count

func serve(customerP: @autoclosure () -> String) { // 添加@autoclosure能自动转化为闭包
    customerP()                        // 执行参数闭包
}

serve(customerP: names.remove(at: 0) ) // 可以将string类型的参数传进去
names.count







